package com.kylin.common.security.filter;

import com.alibaba.fastjson2.JSON;
import com.kylin.common.core.util.SpringUtils;
import com.kylin.common.redis.service.RedisService;
import com.kylin.common.security.config.SecurityProperties;
import com.kylin.common.security.domain.ClaimsInfo;
import com.kylin.common.security.domain.LoginUser;
import com.kylin.common.security.exception.AuthErrorMessage;
import com.kylin.common.security.util.JwtUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

/**
 * 自定义认证过滤器
 * @author wuhao
 * @version 1.0 - 2022/8/15
 */
public class JwtTokenAuthenticationFilter extends OncePerRequestFilter {

    private SecurityProperties securityProperties;

    public JwtTokenAuthenticationFilter(SecurityProperties securityProperties) {
        this.securityProperties = securityProperties;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        logger.info("=================" + request.getRequestURI());
        //不需要鉴权过滤
//        PathMatcher matcher = new AntPathMatcher();
//        if (securityProperties.getIgnoreUrls().stream().anyMatch(i -> matcher.match(i, request.getRequestURI()))) {
//            chain.doFilter(request, response);
//            return;
//        }

        // 1.获取Token字符串，token 置于 header 里
        String token = request.getHeader("token");
        if(!StringUtils.hasText(token)) {
            token = request.getHeader("Sec-WebSocket-Protocol");
        }
        if (!StringUtils.hasText(token)) {
            token = request.getParameter("token");
        }

        if(!StringUtils.hasText(token)) {
            //放行，让后面的过滤器去处理
            chain.doFilter(request, response);
            return;
        }

        // 2.解析token
        ClaimsInfo claimsInfo;
        try {
            Claims claims = JwtUtils.parseJwt(token);
            claimsInfo = JSON.parseObject(claims.getSubject(), ClaimsInfo.class);
        }catch (ExpiredJwtException e) {
            throw new InternalAuthenticationServiceException(AuthErrorMessage.TOKEN_EXPIRED.getMessage());
        }
        catch (Exception e) {
            throw new InternalAuthenticationServiceException(AuthErrorMessage.TOKEN_ERROR.getMessage());
        }

        // 3.根据userId获取用户信息
        RedisService redisService = SpringUtils.getBean(RedisService.class);
        LoginUser loginUser = redisService.getCacheObject(claimsInfo.getTokenKey());
        if(Objects.isNull(loginUser)) {
            throw new InternalAuthenticationServiceException(AuthErrorMessage.USER_NO_LOGIN.getMessage());
        }

        // 4.封装Authentication
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                new UsernamePasswordAuthenticationToken(loginUser, token, loginUser.getAuthorities());

        // 5.存入SecurityContextHolder
        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);

        // 放行，让其他过滤器继续执行
        chain.doFilter(request, response);
    }
}
